package com.zhihaoliang.coroutine.buss.excep.func

import com.zhihaoliang.coroutine.util.log
import kotlinx.coroutines.*

/**
 * @author 支豪亮
 * @date 2022/10/28 17:26
 * @des
 */
object Supervision {
    fun supervisionJob(mainScope:CoroutineScope) = mainScope.launch {
        val supervisor = SupervisorJob()
        with(CoroutineScope(coroutineContext + supervisor)) {
            // launch the first child -- its exception is ignored for this example (don't do this in practice!)
            val firstChild = launch(CoroutineExceptionHandler { _, _ ->  }) {
                log("The first child is failing")
                throw AssertionError("The first child is cancelled")
            }
            // launch the second child
            val secondChild = launch {
                firstChild.join()
                // Cancellation of the first child is not propagated to the second child
                log("The first child is cancelled: ${firstChild.isCancelled}, but the second one is still active")
                try {
                    delay(Long.MAX_VALUE)
                } finally {
                    // But cancellation of the supervisor is propagated
                    log("The second child is cancelled because the supervisor was cancelled")
                }
            }
            // wait until the first child fails & completes
            firstChild.join()
            log("Cancelling the supervisor")
            supervisor.cancel()
            secondChild.join()
        }
    }

    fun supervisionScope(mainScope:CoroutineScope) = mainScope.launch {
        try {
            supervisorScope {
                val child = launch {
                    try {
                        log("The child is sleeping")
                        delay(Long.MAX_VALUE)
                    } finally {
                        log("The child is cancelled")
                    }
                }
                // Give our child a chance to execute and print using yield
                yield()
                log("Throwing an exception from the scope")
                throw AssertionError()
            }
        } catch(e: AssertionError) {
            log("Caught an assertion error")
        }
    }
}